package org.gwtEss.table;

import java.util.ArrayList;
import java.util.List;

import org.gwtEss.link.LabelLink;
import org.gwtEss.menu.Menu;
import org.gwtEss.menu.MenuItem;
import org.gwtEss.menu.MenuItemBase;
import org.gwtEss.menu.MenuItemSeperator;
import org.gwtEss.menu.MenuItemTitle;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;

public abstract class HeaderTableNew <VO> extends Composite{
	private Cols<VO> cols;
	private HorizontalPanel mainPanel = new HorizontalPanel();
	private Cols<VO> visibleCols = new Cols<VO>();
	private static final int LAST_COL_WIDTH = 17;
	private static final int DETAIL_TABLE_WIDTH = 170;

	public HeaderTableNew(Cols<VO> cols/*, int pxWidth*/) {
		this.cols = cols; 
		initWidget(mainPanel);
		mainPanel.setSpacing(0);
		mainPanel.addStyleName("table-header");
		renderVisibleCols();
	}
	
	private int calculateColWidth(ColWidget colWidget, int actualAvailableWidth, int widthSoFar, int visibleColNum){
		int suggestedColWidth = colWidget.getSuggestedWidth();
		int colW;
		if (visibleColNum != visibleCols.size()-1 && suggestedColWidth > HeaderTableColWidget.MIN_WIDTH && (actualAvailableWidth - (widthSoFar + suggestedColWidth) > ((visibleCols.size() - visibleColNum)*HeaderTableColWidget.MIN_WIDTH))){
			colW = suggestedColWidth;
		}else{
			colW = (int)Math.floor (((double)(actualAvailableWidth - widthSoFar))/((double)(visibleCols.size() - visibleColNum)));
		}
		return colW;
	}
	private ColWidget sortCol; 
	private HeaderTableColWidget createHeaderTableColWidget(final ColWidget thisCol){
		HeaderTableColWidget w = new HeaderTableColWidget(thisCol.getColName(), visibleCols.indexOf(thisCol)==(visibleCols.size() - 1)){
			@Override
			public void onColResizeBegin() {
				onResizeBegin(thisCol, visibleCols.get(visibleCols.indexOf(thisCol)+1));
				//Widgets should be added in such a way that array index out of bound should not occur in above stmt. 
			}

			@Override
			public void onColResizeEnd() {
				thisCol.setColWidth(this.getOffsetWidth()/*getWidth()*/);
				ColWidget rightCol = visibleCols.get(visibleCols.indexOf(thisCol)+1);
				rightCol.setColWidth(((HeaderTableColWidget)mainPanel.getWidget(mainPanel.getWidgetIndex(this)+1)).getOffsetWidth()/*getWidth()*/);
				onResizeEnd(thisCol, rightCol);
			}

			@Override
			public void onColSort(Boolean sortAsc) {
				if (sortCol != null && sortCol != thisCol){
					sortCol.setSortAsc(null);
//					((HeaderTableColWidget)mainPanel.getWidget(visibleCols.indexOf(sortCol))).setSortOrder(null);
					getHeaderTableColWidget(sortCol).setSortOrder(null);
				}
				onSort(thisCol, sortAsc);
				sortCol = thisCol;
			}

			@Override
			public void onFilterMenuSelect(
					FetchCompleteCallBack<FilterMenuItem> filterListCallBack) {
				HeaderTableNew.this.onFilterMenuSelect(thisCol, filterListCallBack);
			}

			@Override
			public void onFilterMenuClose(List<FilterMenuItem> filterCriterias) {
				HeaderTableNew.this.onFilterMenuClose(thisCol, filterCriterias);
			}
		};
//		w.setFilterMenuVisible(true);
		return w;
	}
	public abstract void onFilterMenuSelect(ColWidget col, FetchCompleteCallBack<FilterMenuItem> filterListCallBack);
	private HeaderTableColWidget getHeaderTableColWidget(ColWidget col){
		return (HeaderTableColWidget) mainPanel.getWidget(visibleCols.indexOf(col));
	}
	private void renderVisibleCols(){
		updateVisibleCols();
		mainPanel.clear();
//		int actualAvailableWidth = /*pxWidth*/ getOffsetWidth() - LAST_COL_WIDTH; 
		int actualAvailableWidth = 350- LAST_COL_WIDTH;
		int widthSoFar = 0, colW;
		
		HeaderTableColWidget thisHeaderTableColWidget = null, rightHeaderTableColWidget = null; 
		
		for (int i=0; i<visibleCols.size(); i++){
			final ColWidget thisCol = visibleCols.get(i);
			final ColWidget rightCol = i==(visibleCols.size() - 1)? null: visibleCols.get(i+1);
			colW = calculateColWidth(thisCol, actualAvailableWidth, widthSoFar, i);
			thisCol.setColWidth(colW);
			if (thisHeaderTableColWidget == null)
				thisHeaderTableColWidget = createHeaderTableColWidget(thisCol);
			else 
				thisHeaderTableColWidget = rightHeaderTableColWidget;
			thisHeaderTableColWidget.setWidth(colW + "px");
			if (rightCol != null){
				rightHeaderTableColWidget = createHeaderTableColWidget(rightCol);
				thisHeaderTableColWidget.associateDependentColWidget(rightHeaderTableColWidget);
			}
				
			mainPanel.add(thisHeaderTableColWidget);
			widthSoFar += thisCol.getColWidth();
		}
		mainPanel.setHorizontalAlignment(HasAlignment.ALIGN_CENTER);
		mainPanel.add(getLastCol());
	}
	final LabelLink lastColumn = new LabelLink("...");
	private LabelLink getLastCol(){
		final Menu headerMenu = new Menu(){

			@Override
			public int getMenuLeft() {
				return lastColumn.getAbsoluteLeft();
			}

			@Override
			public int getMenuTop() {
				return lastColumn.getAbsoluteTop()+ lastColumn.getOffsetHeight();
			}}; 
		headerMenu.setData(new ArrayList<MenuItemBase>(){
			{
				int colsSize = cols.size();
				add(new MenuItemTitle("Columns"));
				
				for (int i=0; i< colsSize; i++){
					final ColWidget col = cols.get(i);
					add(new MenuItem(col.getColName()) {
						private CheckBox chk = new CheckBox();
						@Override
						public boolean onSelect() {
							boolean val = !chk.getValue();
							System.out.println("val: " + val);
							chk.setValue(val);
							col.setVisible(val);
							renderVisibleCols();
							onColVisibilityChanged(cols);
//							updateVisibleCols();
							return false;
						}
						{
							chk.addClickHandler(new ClickHandler() {//checkbox click event conflicts with menu item select event. that is why this stupid fix. 
								
								@Override
								public void onClick(ClickEvent event) {
									chk.setValue(!chk.getValue());	
								}
							});
							chk.setValue(visibleCols.indexOf(col) != -1);
							setIcon(chk);
						}
					});
				}
				
			}
		});
		lastColumn.addClickHandler(new ClickHandler(){

			public void onClick(ClickEvent event) {
//				showHeaderDetailsPopup(event.getNativeEvent().getClientX(), event.getNativeEvent().getClientY());
				headerMenu.show();
			}
			
		});
		lastColumn.setWidth(LAST_COL_WIDTH + "px");
		return lastColumn;
	}

	private void updateVisibleCols(){
		visibleCols.clear();
		for (ColWidget col: cols)
			if (col.isVisible())
			visibleCols.add(col);
	}
	public abstract void onColVisibilityChanged(Cols<VO> visibleCols);
	public abstract void onResizeBegin(ColWidget leftCol, ColWidget rightCol);
	public abstract void onResizeEnd(ColWidget leftCol, ColWidget rightCol);
	public abstract void onSort(ColWidget col, Boolean asc);
	public abstract void onFilterMenuClose(ColWidget col, List<FilterMenuItem> filterCriterias);
}
